package com.example.crawler.schedule;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.crawler.excel.EasyExcelUtil;
import com.example.crawler.excel.pojo.HKCompany;
import com.example.crawler.excel.pojo.NasdqCompany;
import com.xxl.job.core.context.XxlJobHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;
import com.xxl.job.core.handler.annotation.XxlJob;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class CrawlerSchedule {

    private List<NasdqCompany> otherList = new ArrayList<>();
    private List<NasdqCompany> filedList = new ArrayList<>();

    
    @XxlJob("crawlerSchedule")
    public void crawlerSchedule() {
        XxlJobHelper.log("XXL-JOB, crawlerProposedSchedule.");
        try {
            long start = System.currentTimeMillis();
            log.info(String.format("开始爬数据: %s", start));
            // 爬取港股数据
            crawlerHkexnewsData();
            log.info(String.format("港股爬数据完成耗时: %s", System.currentTimeMillis() - start));

            // 爬取纳斯达克数据
            crawlerNasdaqData();
            log.info(String.format("美股爬数据完成耗时: %s", System.currentTimeMillis() - start));
            
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    private void crawlerNasdaqData() throws IOException, ParseException {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        // 网址
        List<String> urlList = new ArrayList<>();
        for (int i = 0; i <= 36; i++){
            String url = "https://api.nasdaq.com/api/ipo/calendar?date=" + year + "-" + (month > 9 ? month : "0" + month); // 纳斯达克
//            String url = "https://api.nasdaq.com/api/ipo/calendar?date=2022-08"; // 纳斯达克
            urlList.add(url);
            if(month-1 >= 1){
                --month;
            } else {
                month = month + 11;
                year = year - 1;
            }
        }

        // 爬取数据
        for (String urlStr : urlList) {
            System.out.println(urlStr);
            crawlerData(urlStr, "nasdaq");
        }

        List<NasdqCompany> tempList = new ArrayList<>();
        Set<String> comNameSet = new HashSet<>();
        for (NasdqCompany nasdqCompany : filedList) {
            if (comNameSet.add(nasdqCompany.getName())) {
                tempList.add(nasdqCompany);
            }
        }
        Set<String> otherComNameSet = otherList.stream().map(NasdqCompany::getName).collect(Collectors.toSet());
        List<NasdqCompany> resultList = new ArrayList<>();
        resultList.addAll(tempList);
        for (NasdqCompany nasdqCompany : tempList) {
            if (!otherComNameSet.add(nasdqCompany.getName())) {
                for (NasdqCompany company : otherList) {
                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                    if (company.getName().equals(nasdqCompany.getName()) && format.parse(company.getDate()).after(format.parse(nasdqCompany.getDate()))) {
                        resultList.remove(nasdqCompany);
                    }
                }
            }
        }

        // 导出数据
        EasyExcelUtil easyExcelUtil = new EasyExcelUtil();
        easyExcelUtil.write(resultList, NasdqCompany.class, "d:\\美股拟上市企业数据.xls");
        System.out.println("OK");
    }

    private void crawlerHkexnewsData() throws IOException {
        List companyList = new ArrayList<>();
        // 网址
        String url1 = "https://www1.hkexnews.hk/ncms/json/eds/appactive_appphip_sehk_c.json?_=1661822681203"; // 披露易 MAIN BOARD
        String url2 = "https://www1.hkexnews.hk/ncms/json/eds/appactive_appphip_gem_c.json?_=1661822681205";  // 披露易 GEM
        List<String> urlList = new ArrayList<>();
        urlList.add(url1);
        urlList.add(url2);

        // 爬取数据
        for (String urlStr : urlList) {
            companyList.addAll(crawlerData(urlStr, "hkexnews"));
        }

        // 导出数据
        EasyExcelUtil easyExcelUtil = new EasyExcelUtil();
        easyExcelUtil.write(companyList, HKCompany.class, "d:\\港股拟上市企业数据.xls");
        System.out.println("OK");
    }

    private List crawlerData(String url, String functionType) throws IOException {
        List companyList = new ArrayList<>();
        //创建HttpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        //创建HttpGet请求
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("User-Agent","PostmanRuntime/7.29.2");

        //设置请求参数
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(100000)            // 设置创建连接的最长时间
                .setConnectionRequestTimeout(50000)   // 设置获取连接的最长时间
                .setSocketTimeout(10 * 100000)        // 设置数据传输的最长时间
                .build();

        httpGet.setConfig(requestConfig);

        CloseableHttpResponse response = null;
        try {
            //使用HttpClient发起请求
            response = httpClient.execute(httpGet);

            //判断响应状态码是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                //如果为200表示请求成功，获取返回数据
                String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                //打印数据
                HashMap hashMap = JSON.parseObject(content, HashMap.class);

                switch(functionType){
                    case "nasdaq":
                        getNasdqResultList(hashMap);
                        break;
                    case "hkexnews":
                        getHkResultList(companyList, hashMap);
                        break;
                    default:
                        break;

                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放连接
            if (response == null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                httpClient.close();
            }
        }
        return companyList;
    }

    public void getHkResultList(List<HKCompany> companyList, HashMap hashMap) {
        JSONArray appList = JSONArray.parseArray(hashMap.get("app").toString());
        for (Object obj : appList) {
            Map map = JSONObject.parseObject(JSONObject.toJSONString(obj), Map.class);
            HKCompany company = new HKCompany();
            String dateStr = getDateStr(String.valueOf(map.get("d")));
            company.setDate(dateStr);
            String contentStr = String.valueOf(map.get("a"));
            company.setName(contentStr);
            companyList.add(company);
        }
    }

    public void getNasdqResultList(HashMap hashMap) {
        // 拟上市企业 = “Filings”申请 - “Priced”定价 - “Withdrawn”撤回
        Map data = JSONObject.parseObject(String.valueOf(hashMap.get("data")), Map.class);
        if(data != null){
            Map priced = JSONObject.parseObject(String.valueOf(data.get("priced")), Map.class);
            Map upcoming = JSONObject.parseObject(String.valueOf(data.get("upcoming")), Map.class);
            Map filed = JSONObject.parseObject(String.valueOf(data.get("filed")), Map.class);
            Map withdrawn = JSONObject.parseObject(String.valueOf(data.get("withdrawn")), Map.class);
            extracted(priced, "priced");
            extracted(upcoming, "upcoming");
            extracted(filed, "filed");
            extracted(withdrawn, "withdrawn");
        }
    }

    private void extracted(Map<String, Object> objectMap, String flag) {
        if(objectMap.get("rows") != null){
            JSONArray rows = JSONArray.parseArray(String.valueOf(objectMap.get("rows")));
            for (Object obj : rows) {
                NasdqCompany company = new NasdqCompany();
                Map map = JSONObject.parseObject(JSONObject.toJSONString(obj), Map.class);
                company.setCompanyCode(map.get("proposedTickerSymbol") == null ? null : String.valueOf(map.get("proposedTickerSymbol")));
                company.setName(String.valueOf(map.get("companyName")));

                switch(flag){
                    case "priced":
                        company.setDate(getDateStr(String.valueOf(map.get("pricedDate"))));
                        otherList.add(company);
                        break;
                    case "upcoming":
                        company.setDate(getDateStr(String.valueOf(map.get("expectedPriceDate"))));
                        otherList.add(company);
                        break;
                    case "filed":
                        company.setDate(getDateStr(String.valueOf(map.get("filedDate"))));
                        filedList.add(company);
                        break;
                    case "withdrawn":
                        company.setDate(getDateStr(String.valueOf(map.get("filedDate"))));
                        otherList.add(company);
                        break;
                    default: break;
                }

            }
        }
    }

    private String getDateStr(String dateStr) {
        return dateStr.substring(6, 10) + "-"
                + dateStr.substring(0, 2) + "-"
                + dateStr.substring(3, 5);
    }


}
